//----------------------------------------------
//            Tasharen Network
// Copyright © 2012-2014 Tasharen Entertainment
//----------------------------------------------

// Note on the UDP lobby: Although it's a better choice than TCP (and plus it allows LAN broadcasts),
// it doesn't seem to work with the Amazon EC2 cloud-hosted servers. They don't seem to accept inbound UDP traffic
// without an active TPC connection from the same source... so it's your choice which protocol to use.

using System;
using System.Diagnostics;
using TNet;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using TNServer;
using LitJson;
using GameData;

/// <summary>
/// This is an example of a stand-alone server. You don't need Unity in order to compile and run it.
/// Running it as-is will start a Game Server on ports 5127 (TCP) and 5128 (UDP), as well as a Lobby Server on port 5129.
/// </summary>

public class Application : IDisposable
{

    public static Application instance;


	string mFilename;
	UPnP mUPnP = null;
	GameServer mGameServer = null;
	LobbyServer mLobbyServer = null;
	Thread mSaveThread = null;

    public static GlobalDB GlobalDb;
    public static GlobalVO MainVO;
    public NumberManager NumManager;
    public static ExcelDataManager ExcelDataManager;

    public delegate bool HandlerRoutine (int type);
	[System.Runtime.InteropServices.DllImport("Kernel32")]
	static extern bool SetConsoleCtrlHandler (HandlerRoutine Handler, bool Add);

	/// <summary>
	/// Function executed by kernel32 when the application exits. This is the only way to reliably detect a closed app in Windows.
	/// </summary>

	bool OnExit (int type) { Dispose(); return true; }


    string fileName = "jc.txt";

    public void SaveData()
    {

        FileStream file = new FileStream(fileName, FileMode.Create);
        StreamWriter fwriter = new StreamWriter(file);
        string str = JsonMapper.ToJson(GlobalDb);
        fwriter.WriteLine(str);
        //

        fwriter.Close();
        file.Close();


    }


    public void LoadData()
    {
        FileStream file = new FileStream(fileName, FileMode.Open);
        StreamReader sr = new StreamReader(file);
        string strLine = sr.ReadLine();
        bool isnew = false;
        if (!string.IsNullOrEmpty(strLine))
        {
            GlobalDb = JsonMapper.ToObject<GlobalDB>(strLine);
            MainVO = GlobalDb.GetCurGlobalVO();
            //获取时间
            //判断时间是否为7天
            
            DateTime eTime = DateTime.Now;
            DateTime vkTime = new DateTime(MainVO.DateTimeTicks);
            int dy = (eTime - vkTime).Days;
            if (dy>=7)
            {
                NewGlobalVO();
                
                isnew = true;
            }

        }
        else
        {
            NewGlobalVO();
            isnew = true;
            Console.WriteLine("ticks=" + MainVO.DateTimeTicks);

        }
        NumManager = new NumberManager(MainVO);
        NumberManager.instance = NumManager;
        sr.Close();
        file.Close();
        if (isnew)
        {
            SaveData();
        }

        //读取认筹数据
        OnInitExcelData();


    }

    public void OnInitExcelData()
    {
        ExcelDataManager = new ExcelDataManager();
        //
        foreach (var p in GlobalDb.GetCurGlobalVO().NewCustomerDatas)
        {
            ExcelDataManager.CustomerDatas.Add(p.Key, p.Value);
        }


        ExcelDataManager.LoadData();

    }



    public void NewGlobalVO()
    {
        //数据

        GlobalVO newMainVO = new GlobalVO();
        if (MainVO!= null)
        {
            if (ExcelDataManager!= null)
            {
                foreach (var p in ExcelDataManager.CustomerDatas)
                {
                    newMainVO.CustomerDatas.Add(p.Key, p.Value);
                }
            }

            for (int i = 0; i < MainVO.batchList.Count; i++)
            {
                newMainVO.AddBatchlistItem(MainVO.batchList[i]);
            }

        }


        MainVO = newMainVO;

        GlobalDb.AddNewGlobalVO(MainVO);

        MainVO.DateTimeTicks = DateTime.Now.Ticks;
        Console.WriteLine("ticks=" + MainVO.DateTimeTicks);

        Application.MainVO = MainVO;
        //号码管理
        NumManager = new NumberManager(MainVO);
        NumberManager.instance = NumManager;

        //创建管理员帐号
        UserInfo ui = new UserInfo();
        ui.username = "admin";
        ui.password = "admin";
        RoleInfo ro = new RoleInfo();
        ro.ID = 1;
        ro.Name = "管理员";
        ro.power = "全部";
        ro.UserInfo = ui;
        ro.UserName = "admin";
        Application.MainVO.AddRoleInfo(ro.UserName, ro);

        //取号
        ui = new UserInfo();
        ui.username = "quhao";
        ui.password = "quhao";
         ro = new RoleInfo();
        ro.ID = 1;
        ro.Name = "取号";
        ro.power = "取号";
        ro.UserInfo = ui;
        ro.UserName = "quhao";
        Application.MainVO.AddRoleInfo(ro.UserName, ro);

        //排号
        ui = new UserInfo();
        ui.username = "paihao";
        ui.password = "paihao";
        ro = new RoleInfo();
        ro.ID = 1;
        ro.Name = "排号";
        ro.power = "排号";
        ro.UserInfo = ui;
        ro.UserName = "paihao";
        Application.MainVO.AddRoleInfo(ro.UserName, ro);

        //抽号
        ui = new UserInfo();
        ui.username = "chouhao";
        ui.password = "chouhao";
        ro = new RoleInfo();
        ro.ID = 1;
        ro.Name = "抽号";
        ro.power = "抽号";
        ro.UserInfo = ui;
        ro.UserName = "chouhao";
        Application.MainVO.AddRoleInfo(ro.UserName, ro);

        //叫号
        ui = new UserInfo();
        ui.username = "jiaohao";
        ui.password = "jiaohao";
        ro = new RoleInfo();
        ro.ID = 1;
        ro.Name = "叫号";
        ro.power = "叫号";
        ro.UserInfo = ui;
        ro.UserName = "jiaohao";
        Application.MainVO.AddRoleInfo(ro.UserName, ro);

        //
        ui = new UserInfo();
        ui.username = "zhanshi";
        ui.password = "zhanshi";
        ro = new RoleInfo();
        ro.ID = 1;
        ro.Name = "展示";
        ro.power = "展示";
        ro.UserInfo = ui;
        ro.UserName = "zhanshi";
        Application.MainVO.AddRoleInfo(ro.UserName, ro);

        ui = new UserInfo();
        ui.username = "yuangong";
        ui.password = "yuangong";
        ro = new RoleInfo();
        ro.ID = 1;
        ro.Name = "员工";
        ro.power = "员工";
        ro.UserInfo = ui;
        ro.UserName = "yuangong";
        Application.MainVO.AddRoleInfo(ro.UserName, ro);

    }

    void InitData()
    {
        
        Console.WriteLine("初始化数据");
        if (!File.Exists(fileName))
        {
            
            FileStream file = new FileStream(fileName, FileMode.Create);
            StreamWriter fwriter = new StreamWriter(file);

            GlobalDb = new GlobalDB();

            NewGlobalVO();

            string str = JsonMapper.ToJson(GlobalDb);
            fwriter.WriteLine(str);
            //

            fwriter.Close();
            file.Close();
            //读取认筹数据
            ExcelDataManager = new ExcelDataManager();
            ExcelDataManager.LoadData();
        }
        else
        {
            LoadData();

        }

    
        //
        if (!MainVO.SetDataDic.ContainsKey("批次"))
        {
            MainVO.SetDataDic.Add("批次","第一批");
        }
    }


	/// <summary>
	/// Start the server.
	/// </summary>

	public void Start (string serverName, int tcpPort, int udpPort, string lobbyAddress, int lobbyPort, bool useTcp, bool service, string fn = "server.dat")
	{
	    Application.instance = this;

        mFilename = fn;
		List<IPAddress> ips = Tools.localAddresses;
		string text = "\n本地 IPs: " + ips.size;

		for (int i = 0; i < ips.size; ++i)
		{
			text += "\n  " + (i + 1) + ": " + ips[i];
			if (ips[i] == TNet.Tools.localAddress) text += " (Primary)";
		}


        InitData();

        Console.WriteLine(text + "\n");
		{
			// Universal Plug & Play is used to determine the external IP address,
			// and to automatically open up ports on the router / gateway.
			mUPnP = new UPnP();
			mUPnP.WaitForThreads();

			if (mUPnP.status == UPnP.Status.Success)
			{
				Console.WriteLine("网关 IP:  " + mUPnP.gatewayAddress);
			}
			else
			{
				Console.WriteLine("网关 IP:  没有找到网关");
				mUPnP = null;
			}
            Console.WriteLine("===================================");
            Console.WriteLine("客户端需要输入IP：");
            Console.WriteLine("外部 IP: " + Tools.externalAddress);
            Console.WriteLine("===================================");

            Console.WriteLine("");

			if (tcpPort > 0)
			{
				mGameServer = new GameServer();
			    GameServer.instance = mGameServer;
                mGameServer.name = serverName;

				if (!string.IsNullOrEmpty(lobbyAddress))
				{
					// Remote lobby address specified, so the lobby link should point to a remote location
					IPEndPoint ip = Tools.ResolveEndPoint(lobbyAddress, lobbyPort);
					if (useTcp) mGameServer.lobbyLink = new TcpLobbyServerLink(ip);
					else mGameServer.lobbyLink = new UdpLobbyServerLink(ip);

				}
				else if (lobbyPort > 0)
				{
					// Server lobby port should match the lobby port on the client
					if (useTcp)
					{
						mLobbyServer = new TcpLobbyServer();
						mLobbyServer.Start(lobbyPort);
						if (mUPnP != null) mUPnP.OpenTCP(lobbyPort, OnPortOpened);
					}
					else
					{
						mLobbyServer = new UdpLobbyServer();
						mLobbyServer.Start(lobbyPort);
						if (mUPnP != null) mUPnP.OpenUDP(lobbyPort, OnPortOpened);
					}

					// Local lobby server
					mGameServer.lobbyLink = new LobbyServerLink(mLobbyServer);
				}

				// Start the actual game server and load the save file
				mGameServer.Start(tcpPort, udpPort);
				mGameServer.LoadFrom(mFilename);
				Console.WriteLine("Loaded " + mFilename);
			}
			else if (lobbyPort > 0)
			{
				if (useTcp)
				{
					if (mUPnP != null) mUPnP.OpenTCP(lobbyPort, OnPortOpened);
					mLobbyServer = new TcpLobbyServer();
					mLobbyServer.Start(lobbyPort);
				}
				else
				{
					if (mUPnP != null) mUPnP.OpenUDP(lobbyPort, OnPortOpened);
					mLobbyServer = new UdpLobbyServer();
					mLobbyServer.Start(lobbyPort);
				}
			}

			// Open up ports on the router / gateway
			if (mUPnP != null)
			{
				if (tcpPort > 0) mUPnP.OpenTCP(tcpPort, OnPortOpened);
				if (udpPort > 0) mUPnP.OpenUDP(udpPort, OnPortOpened);
			}

			// This approach doesn't work on Windows 7 and higher.
			AppDomain.CurrentDomain.ProcessExit += new EventHandler(delegate(object sender, EventArgs e) { Dispose(); });

			// This approach works only on Windows
			try { SetConsoleCtrlHandler(new HandlerRoutine(OnExit), true); }
			catch (Exception) { }

			// Save periodically
			mSaveThread = new Thread(delegate(object obj)
			{
				for (; ; )
				{
					Thread.Sleep(120000);
					if (mGameServer != null) mGameServer.SaveTo(mFilename);
				}
			});
			mSaveThread.Start();

			for (; ; )
			{
				if (!service)
				{
                    Console.WriteLine("第一版本 1.0.0 2016/2/3");
                    Console.WriteLine("输入‘q’:退出, 'S':保存数据,'qns':推出不保存 然后回车");

                    //Console.WriteLine("Press 'q' followed by ENTER when you want to quit.\n");

                    string command = Console.ReadLine();
				    if (command == "q")
				    {
                        Application.instance.SaveData();
                        break;
				    }
				    if (command == "qns")
				    {
                        break;
                    }
				    if (command == "h")
				    {
                        Console.WriteLine("1:输入‘sc’:保存客户取号数据");
                        Console.WriteLine("2:输入‘q’:退出");
                        Console.WriteLine("3:输入‘s’:保存");
                        Console.WriteLine("4:输入‘rs’:重新领取");

                    }
                    if (command == "sc")
                    {

                        ExcelDataManager.WriteExcelQue();
                    }
                    if (command == "s")
					{
                        Application.instance.SaveData();

                        mGameServer.SaveTo(mFilename);
						Console.WriteLine("Saved as " + mFilename);
					}
				    if (command == "rs")
				    {
				        OnInitExcelData();
                        NewGlobalVO();
				        Logic.RestartReceiveNum();
				    }
				}
				else Thread.Sleep(10000);
			}
			Console.WriteLine("Shutting down...");
			Dispose();
		}

		if (!service)
		{
			Console.WriteLine("The server has shut down. Press ENTER to terminate the application.");
			Console.ReadLine();
		}
	}






	/// <summary>
	/// Stop the server.
	/// </summary>

	public void Dispose ()
	{
		if (mSaveThread != null)
		{
			mSaveThread.Abort();
			mSaveThread = null;
		}

		// Stop the game server
		if (mGameServer != null)
		{
			Console.WriteLine("Saved as " + mFilename);
			mGameServer.SaveTo(mFilename);
			mGameServer.Stop();
			mGameServer = null;
		}

		// Stop the lobby server
		if (mLobbyServer != null)
		{
			mLobbyServer.Stop();
			mLobbyServer = null;
		}

		// Close all opened ports
		if (mUPnP != null)
		{
			mUPnP.Close();
			mUPnP.WaitForThreads();
			mUPnP = null;
		}
	}

	/// <summary>
	/// UPnP notification of a port being open.
	/// </summary>

	void OnPortOpened (UPnP up, int port, ProtocolType protocol, bool success)
	{
		if (success)
		{
			Console.WriteLine("UPnP: " + protocol.ToString().ToUpper() + " port " + port + " was opened successfully.");
		}
		else
		{
			Console.WriteLine("UPnP: Unable to open " + protocol.ToString().ToUpper() + " port " + port);
		}
	}

	/// <summary>
	/// Application entry point -- parse the parameters.
	/// </summary>

	static int Main (string[] args)
	{
		if (args == null || args.Length == 0)
		{
            Console.WriteLine("------ 筠城置业排号系统服务器 ------");
            Console.WriteLine("服务器默认参数");
			Console.WriteLine("可指定参数，设置方法如下:\n");
			Console.WriteLine("   -name \"Your Server\"      <-- 设置服务器名称");
			Console.WriteLine("   -world \"Your World\"      <-- 选择世界频道");
			Console.WriteLine("   -tcp [port]              <-- TCP port ");
			Console.WriteLine("   -public                  <-- 是否公开");
			Console.WriteLine("   -service                 <-- 开启服务");
			Console.WriteLine("\n例如:");
			Console.WriteLine("  WWServer -name \"My Server\" -tcp 5127 -public");

			args = new string[] { "-name", "Windward Server", "-tcp", "5127", "-world", "World" };
		}

		string serverName = "Windward Server";
		string worldName = "World";
		int tcpPort = 0;
		int udpPort = 0;
		string lobbyAddress = null;
		int lobbyPort = 0;
		bool tcpLobby = false;
		bool service = false;

		for (int i = 0; i < args.Length; )
		{
			string param = args[i];
			string val0 = (i + 1 < args.Length) ? args[i + 1] : null;
			string val1 = (i + 2 < args.Length) ? args[i + 2] : null;

			if (val0 != null && val0.StartsWith("-"))
			{
				val0 = null;
				val1 = null;
			}
			else if (val1 != null && val1.StartsWith("-"))
			{
				val1 = null;
			}

			if (param == "-name")
			{
				if (val0 != null) serverName = val0;
			}
			else if (param == "-world")
			{
				if (val0 != null) worldName = val0;
			}
			else if (param == "-tcp")
			{
				if (val0 != null) int.TryParse(val0, out tcpPort);
			}
			else if (param == "-udp")
			{
				if (val0 != null) int.TryParse(val0, out udpPort);
			}
			else if (param == "-ip")
			{
				if (val0 != null) UdpProtocol.defaultNetworkInterface = Tools.ResolveAddress(val0);
			}
			else if (param == "-tcpLobby")
			{
				if (val1 != null)
				{
					lobbyAddress = val0;
					int.TryParse(val1, out lobbyPort);
				}
				else int.TryParse(val0, out lobbyPort);
				tcpLobby = true;
			}
			else if (param == "-udpLobby")
			{
				if (val1 != null)
				{
					lobbyAddress = val0;
					int.TryParse(val1, out lobbyPort);
				}
				else int.TryParse(val0, out lobbyPort);
				tcpLobby = false;
			}
			else if (param == "-lobby")
			{
				if (val0 != null) lobbyAddress = val0;
			}
			else if (param == "-public")
			{
				lobbyAddress = "server.tasharen.com";
				lobbyPort = 5190;
				tcpLobby = true;
			}
			else if (param == "-service")
			{
				service = true;
			}

			if (val1 != null) i += 3;
			else if (val0 != null) i += 2;
			else ++i;
		}

		if (string.IsNullOrEmpty(worldName)) worldName = "World";
		worldName = Tools.GetDocumentsPath("Windward/Worlds/" + worldName + ".dat");
		Application app = new Application();
		app.Start(serverName, tcpPort, udpPort, lobbyAddress, lobbyPort, tcpLobby, service, worldName);
		return 0;
	}
}
